package com.test.license;





import com.test.Protection.C;
import com.test.Protection.Constant;
import com.test.security.a.RSAEncrypt;

import java.io.*;
import java.nio.charset.Charset;
import java.util.Properties;
import java.util.zip.CRC32;

/**
 * @author: zouren
 * @date: 2022/3/11
 * @description:
 */

public class LicenseReader {
    private License license;
    private boolean licenseRead = false;
    public String licenseFileName = "/conf/license";
    private String sp;

    public String getSp() {
        return sp;
    }
    //    public static  String LICENSE_PRI_KEY = "licenseType";


    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
    private String decryptPriKey;

    public void setDecryptPriKey(String decryptPriKey) {
        this.decryptPriKey = decryptPriKey;
    }

    public String getDecryptPriKey() {
        return decryptPriKey;
    }

    public License getLicense() {
        return this.getLicense(false);
    }

    public void setLicense(License license) {
        this.license = license;
    }

    public String getLicenseFileName() {
        return licenseFileName;
    }

    public License getLicense(boolean forceRead) {
        if (forceRead) {
            this.readLicense();
        }
        return this.license;
    }

    public synchronized void readLicense() {
        InputStream licenseInputStream = this.getLicenseInputStream();
        int max = 1;
        while (max<=10) {
            System.out.println(max);
            try {
                if (licenseInputStream != null&&licenseInputStream.available()>0) {
                    this.readLicense(licenseInputStream);
                    break;
                } else {
                    licenseInputStream = this.getLicenseInputStream();
                }
            } catch (Exception e) {
                Constant.error(e);
            }finally {
                max++;
            }
        }

    }

    private void readLicense(InputStream licenseInputStream) throws IOException {
        this.license = null;
        Object var3 = null;

        byte[] licenseBytes;
        try {
            licenseBytes = this.smartGetLicenseBytes(licenseInputStream);
        } finally {
            licenseInputStream.close();
        }
//        System.out.println("readLicense: "+new String(licenseBytes,DEFAULT_CHARSET));
        if (licenseBytes != null) {
            byte[] bytes = decodeLicense(licenseBytes);
            readLicense(bytes);
            if (this.license == null) {
                throw new RuntimeException(" License  init  Exception");
            }
        }
    }

    private byte[] decodeLicense(byte[] aLicenseBytes) {
        byte[] result = aLicenseBytes;
        try {
            result = RSAEncrypt.decrypt(result, decryptPriKey);
        } catch (Exception e) {
            result = null;
            Constant.error(e);
        }
//        System.out.println("decodeLicense: "+new String(result,DEFAULT_CHARSET));
        return result;
    }

    private void readLicense(byte[] aLicenseBytes) {
        try {
//            System.out.println("readLicense:"+new String(aLicenseBytes,DEFAULT_CHARSET));
            ByteArrayInputStream inputStream = new ByteArrayInputStream(aLicenseBytes);

            try {
                Properties properties = new Properties();
                properties.load(inputStream);
                if (!C.a(properties)) {
                    throw new RuntimeException("License sign is err ");
                }
                this.license = new License();
                license.init(properties);
                this.sp = properties.getProperty("sp");
            } finally {
                inputStream.close();
            }
        } catch (Exception e) {
            this.license = null;
            Constant.error(e);
        }
    }


    private InputStream getLicenseInputStream() {
        InputStream licenseInputStream = this.getLicenseFileInputStream();
        if (licenseInputStream == null) {
            licenseInputStream = this.getLicenseResourceInputStream();
        }

        return licenseInputStream;
    }

    private byte[] smartGetLicenseBytes(InputStream aLicenseInputStream) {
        byte[] result = this.getLicenseBytes(aLicenseInputStream);
        if (result == null) {
            throw new RuntimeException("get License  bytes out dated");
        } else {
            return result;
        }
    }

    private byte[] getLicenseBytes(InputStream aLicenseInputStream) {
        byte[] result = null;
        DataInputStream dataInputStream = new DataInputStream(aLicenseInputStream);
        try {
            String productID = dataInputStream.readUTF();
            long savedCRC = dataInputStream.readLong();
            result = dataInputStream.readUTF().getBytes(DEFAULT_CHARSET);
            CRC32 crc32 = new CRC32();
            crc32.update(result);
            if (savedCRC != crc32.getValue() && aLicenseInputStream instanceof FileInputStream) {
                result = null;
            }
        } catch (IOException e) {
            Constant.error(e);
            result = null;
        }

        return result;
    }

    private File getLicenseFile() {
        File licenseFile = new File(System.getProperties().getProperty("user.home"), this.licenseFileName);
        return licenseFile;
    }

    private InputStream getLicenseFileInputStream() {
        InputStream result = null;
        if (this.licenseFileName == null) {
            throw new IllegalStateException("License file name is not specified");
        } else {
            try {
                File licenseFile = this.getLicenseFile();
                if (licenseFile.canRead()) {
                    result = new FileInputStream(licenseFile);
                }
            } catch (FileNotFoundException e) {
                Constant.error(e);
            }
            return result;
        }
    }

    private InputStream getLicenseResourceInputStream() {
        InputStream result = null;
        if (this.licenseFileName != null) {
            result = LicenseReader.class.getResourceAsStream(this.licenseFileName);
        }
        return result;
    }

}
